package com.asa.group.ring;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import com.asa.group.Group;
import com.asa.group.ObjectFunction;
import com.asa.group.ObjectFunction2;
import com.asa.group.Shuffle;

/**
 * 环论 环的定义 如果一个非空集合 R 上定义了两个二元运算 + 和 * ，分别称为加法和乘法，满足： （1） (R,+) 是Abel群 （2） (R,*)
 * 是半群 （3）乘法对于加法满足左分配律、右分配律，即对于 任意的a，b,c属于R ，有 (a+b)*c=a*c+a*b 且 c*(a+b)=a*c+a*b
 * 则称 R 关于运算 +,* 构成一个环（ring），记为 (R,+,*) ，或简记为 R 。
 * 
 * 
 * 
 * 免得再去查定义 半群：满足包含的任意元素运算后依然属于自己，满足结合律
 * 
 * 其实让我感觉奇怪的是，没有把单位元和零元单独拿出来讨论
 * 
 * 
 * 
 * @author asa
 * 
 *         多项式定理 (a+b)^n = 累加从（k=0到n）( 组合(n,k) a^(n-k) b^k)
 * 
 *         (a1+a2+...+am)^n = 累加从（k1+k2+..km=n）( 组合(n,(k1,k2..km)) a1^k1
 *         a2^k2...) ki是变化的
 *
 *
 *         (a+b)(a-b) = a^2 - b^2 对于环不一定成立，(R,*) 必须是幺半群才行
 *
 *
 */
public class Ring {

	
	/**
	 * 判断是否是环
	 * @param <T>
	 * @param list
	 * @param f1
	 * @param f2
	 * @param e
	 * @return
	 */
	public static <T> boolean isRing(ArrayList<T> list, ObjectFunction<T> f1, ObjectFunction<T> f2, T e) {

		boolean ableGroup = Group.isAbleGroup(list, f1, e);
		if (!ableGroup) {
			return false;
		}

		boolean groupSemigroup = Group.isGroupSemigroup(list, f2);

		if (!groupSemigroup) {
			return false;
		}

//		（3）乘法对于加法满足左分配律、右分配律，即对于 任意的a，b,c属于R ，有 (a+b)*c=a*c+a*b 且 c*(a+b)=a*c+a*b 

		boolean fenpeilv = isFenpeilv(list, f1, f2);

		if (!fenpeilv) {
			return false;
		}

		return true;
	}

	
	/**
	 * 判断是否满足分配律
	 * @param <T>
	 * @param list
	 * @param f1
	 * @param f2
	 * @return
	 */
	private static <T> boolean isFenpeilv(ArrayList<T> list, ObjectFunction<T> f1, ObjectFunction<T> f2) {
		ArrayList<T> buffer = new ArrayList<T>();

		buffer.addAll(list);
		buffer.addAll(list);
		buffer.addAll(list);

		List<int[]> combination = Shuffle.Combination(buffer.size(), 3);

		for (int i = 0; i < combination.size(); i++) {
			int[] js = combination.get(i);
			List<int[]> permutation = Shuffle.Permutation(js);

			for (int j = 0; j < permutation.size(); j++) {

				int[] ks = permutation.get(j);

				T t1 = buffer.get(ks[0]);
				T t2 = buffer.get(ks[1]);
				T t3 = buffer.get(ks[2]);

				T hanshu1 = f1.hanshu(t1, t2);
				T hanshu2 = f2.hanshu(hanshu1, t3);

				T hanshu3 = f2.hanshu(t1, t3);
				T hanshu4 = f2.hanshu(t2, t3);
				T hanshu5 = f1.hanshu(hanshu3, hanshu4);

				if (!hanshu2.equals(hanshu5)) {
					return false;
				}

			}

		}
		return true;
	}

	
	
	
	/**
	 * 判断是否是子环
	 * 
	 * 子环
		设 (R,+,*) 是环， S 是 R 的非空子集，如果 (S,+,*) 也是环，则称 S 是环 R 的子环（subring）。
	 * 
	 * 
	 * 
	 */
	
	public static<T> boolean isRingSon(ArrayList<T> list1, ArrayList<T> list2
			,ObjectFunction<T> f1, ObjectFunction<T> f2,T e) {
		
		boolean containtAll = Group.containtAll(list2, list1);
		
		if (!containtAll) {
			return false;
		}
		boolean ring = isRing(list2, f1, f2, e);
		if (!ring) {
			return false;
		}
		
		
		return true;
	}
	
	
	/**
	 * 理想，默认是左理想，理想只需要是集合间就能存在的定义
	 * 定义：设S≤R，若对任意的r∈R，s∈S，rs∈S且sr∈S，则称S为R的一个理想，记为
		S  R；此时{R/S，+，*}为环，叫做环R关于其理想S的商环；
	 * 
	 */
	public static<T> boolean isRingIdea(ArrayList<T> list1, ArrayList<T> list2
			,ObjectFunction<T> f1, ObjectFunction<T> f2) {//f1没有被用到
		
		if(list1==null||list1.size()==0) {
			return false;
		}
			
		
		
		for (int i = 0; i < list1.size(); i++) {
			
			for (int j = 0; j < list2.size(); j++) {
				T t = list1.get(i);
				T t2 = list2.get(j);
				
				T hanshu = f2.hanshu(t, t2);
				T hanshu2 = f2.hanshu(t2, t);

				boolean contains = list1.contains(hanshu);
				if (!contains) {
					return false;
				}
				
				
				boolean contains2 = list1.contains(hanshu2);
				
				if (!contains2) {
					return false;
				}
			}
			
		}
		
		
		return true;
	}
	
	/**
	 * 判断某个元素是否是主理想中的元素
	 * 主理想
	 * 由环R中一个非零元x生成的理想asa记作(a)称为环R的主理想。				这个条件有点苛刻，感觉难以想象出是什么情况
	 * 
	 * x属于R，xR = asa，显然asa是个集合，如果asa恰好满足理想的定义，那么我们称asa为环的主理想，我们一般把asa记作(a)
	 * 
	 * 
	 * 
	 */
	public static<T> boolean isPrincipalIdealElement(ArrayList<T> list
			,ObjectFunction<T> f1, ObjectFunction<T> f2,T e){
		
		boolean contains = list.contains(e);
		
		if (!contains) {
			return false;
		}
		
		
		ArrayList<T> asa = new ArrayList<>();
		
		
		for (int i = 0; i < list.size(); i++) {
			T t = list.get(i);
			
			T hanshu = f2.hanshu(e, t);
			asa.add(hanshu);
		}
		
		
		boolean ringIdea = isRingIdea(asa, list, f1, f2);
		
		
		if (!ringIdea) {
			return false;
		}
		
		
		return true;
		
		
	}
	
	
	
	
	
	
	
	
	
	
	
	
	/**
	 * 获得一个商环
	 * 前提是list1是list2的理性
	 * @param <T>
	 * @param list1
	 * @param list2
	 * @param f1
	 * @param f2
	 * @param e
	 * @return
	 */
	public static<T> ArrayList<ArrayList<T>> isRingFactor(ArrayList<T> list1, ArrayList<T> list2
			,ObjectFunction<T> f1, ObjectFunction<T> f2,ObjectFunction<T> asa,T e) {
		
		ArrayList<ArrayList<T>> result = new ArrayList<ArrayList<T>>();
		for (int i = 0; i < list2.size(); i++) {
			
			T t = list2.get(i);
			
			ArrayList<T> buffer = new ArrayList<T>();
			for (int j = 0; j < list1.size(); j++) {
				
				T t2 = list1.get(i);
				
				T hanshu = asa.hanshu(t, t2);
				buffer.add(hanshu);
				
			}
			
			result.add(buffer);	
			
		}
		
		
		return result;
		
	}
	
	
	
	
	
	/**
	 * 环同态
	 * 环同态定义：满足f(a+b)=f(a)+f(b) ，f(ab)=f(a)f(b) 的环R到环S的映射f叫环同态，
	 * 可自然定义单同态、满同态，同构。易见：f(0)=0,f(-a)=-f(a).
	 * 
	 * 
	 */
	
	
	public static<T,S> boolean isHomomorphism(ArrayList<T> list1, ArrayList<S> list2,
			ObjectFunction<T> list1f1, ObjectFunction<T> list1f2,
			ObjectFunction<S> list2f1, ObjectFunction<S> list2f2,
			ObjectFunction2<T, S> f) {
		// TODO Auto-generated method stub
		
		
		List<T> asa = new ArrayList<T>();
		asa.addAll(list1);
		asa.addAll(list1);
		
		List<int[]> combination = Shuffle.Combination(asa.size(), 2);
		
		
		//f1的计算		f(a+b)=f(a)+f(b)
		for (int i = 0; i < combination.size(); i++) {
			int[] js = combination.get(i);
			
			//判断是否满足f(a*b) = f(a)*f(b)
			T t1 = asa.get(js[0]);
			T t2 = asa.get(js[1]);
			
			S s1 = f.hanshu(t1);
			S s2 = f.hanshu(t2);
			
			

			T hanshu1 = list1f1.hanshu(t1, t2);
			S s3 = f.hanshu(hanshu1);
			S hanshuS1 = list2f1.hanshu(s1, s2);
			
			if (!s3.equals(hanshuS1)) {
				return false;
			}
			
			
			T hanshu2 = list1f1.hanshu(t2, t1);
			S s4 = f.hanshu(hanshu2);
			S hanshuS2 = list2f1.hanshu(s1, s2);

			if (!s4.equals(hanshuS2)) {
				return false;
			}
			
			if (list2.contains(s1)&&list2.contains(s2)&&list2.contains(s3)&&list2.contains(s4)
					&&list2.contains(hanshuS1)&&list2.contains(hanshuS2)) {
				continue;
			}else {
				return false;
			}
			
			
			
		}
		
		
		//f2的计算		f(ab)=f(a)f(b)
		for (int i = 0; i < combination.size(); i++) {
			int[] js = combination.get(i);
			
			//判断是否满足f(a*b) = f(a)*f(b)
			T t1 = asa.get(js[0]);
			T t2 = asa.get(js[1]);
			
			S s1 = f.hanshu(t1);
			S s2 = f.hanshu(t2);
			
			

			T hanshu1 = list1f2.hanshu(t1, t2);
			S s3 = f.hanshu(hanshu1);
			S hanshuS1 = list2f2.hanshu(s1, s2);
			
			if (!s3.equals(hanshuS1)) {
				return false;
			}
			
			
			T hanshu2 = list1f2.hanshu(t2, t1);
			S s4 = f.hanshu(hanshu2);
			S hanshuS2 = list2f2.hanshu(s1, s2);

			if (!s4.equals(hanshuS2)) {
				return false;
			}
			
			if (list2.contains(s1)&&list2.contains(s2)&&list2.contains(s3)&&list2.contains(s4)
					&&list2.contains(hanshuS1)&&list2.contains(hanshuS2)) {
				continue;
			}else {
				return false;
			}
			
			
			
		}
		
		
		
		
		
		
		return true;
	}
	
	
	
	
	/**
	 * 环同构
	 * 判断环同构
	 * 双射
	 * @param <T>
	 * @param <S>
	 * @param list1
	 * @param list2
	 * @param list1f1
	 * @param list1f2
	 * @param list2f1
	 * @param list2f2
	 * @param f
	 * @return
	 */
	public static<T,S> boolean isomorphism(ArrayList<T> list1, ArrayList<S> list2,
			ObjectFunction<T> list1f1, ObjectFunction<T> list1f2,
			ObjectFunction<S> list2f1, ObjectFunction<S> list2f2,
			ObjectFunction2<T, S> f) {
		
		
		boolean isshuangshe = Group.isshuangshe(list1, list2, f);

		if (!isshuangshe) {
			return false;
		}
		
		boolean homomorphism = isHomomorphism(list1, list2, list1f1, list1f2, list2f1, list2f2, f);
		
		if (!homomorphism) {
			return false;
		}
		
		
		
		return true;
		
	
	}
	
	
	
	
	
	/**
	 * 判断是否是整环
	 * 
	 * 
	 * Definition: integral domain
		如果一个环没有零因子，则称它是整环，也就是说，对于任意的 a,b属于R ，如果 ab=0 ，则 a=0或b=0
	 * 
	 * 
	 * 
	 * 设 0！=a属于R ，如果存在一个 0！=b属于R ，使得 ab=0 ，则称 a 是一个零因子。
	 * 
	 * 
	 * 
	 * 
	 */
	
	public static<T> boolean isintegral(ArrayList<T> list, ObjectFunction<T> f1, ObjectFunction<T> f2) {
		T findZero = Group.findZero(list, f2);
		//没有发现零因子
		return findZero==null;
	}
	
	
	
	

	
	
	
	
	
	
	
	
	
	
	
	/**
	 * 主理想整环
		如果环 R 是整环，且它的任一理想均为某个元的主理想，则该环称为主理想整环（principal ideal domain，PID）。
	 *
	 *
	 *它的任一理想均为某个元的主理想，这句话包含的概念太多了，我把它拆开来慢慢说
	 *R是环，那么它的理想asa就是它的真子集，然后理想asa里面的元素必须能和S里面元素乘运算
	 *得出的新的元素依然再asa中，然后asa是主理想还需要满足asa是由xR得出的，其中x必须属于R
	 *
	 *
	 *设 R 是非零环，如果 R 是含单位元的环，且是交换环，且是无零因子环，则称 R 是整环（domain，integral domain）。	这个可以对比整数的概念
	 *
	 *看似一句话就完事了，但内容极为丰富
	 *
	 *问题来了，你怎么找到所有的理想？
	 *		答：便利所有子集，进行判断
	 *
	 *你怎么判断asa是主理想
	 *		答：x属于R，遍历计算xR，得出一个集合，判断是否asa在这个集合里
	 *
	 *PID必定是UFD，而有限环必定不是UFD，有限环必不能是PID？？
	 *
	 *
	 */
	public static<T> boolean isPID(ArrayList<T> list, ObjectFunction<T> f1, ObjectFunction<T> f2) {
		boolean isintegral = isintegral(list, f1, f2);
		
		if (!isintegral) {//先判断是否是整环
			return false;
		}
		
		
		//找到所有的理想
		//先找出所有子集
		ArrayList<ArrayList<T>> ziji = zijilist(list);
		
		
		ArrayList<ArrayList<T>> listPID = new ArrayList<ArrayList<T>>();//记录所有的理想

		for (int i = 0; i < ziji.size(); i++) {
			ArrayList<T> zi = ziji.get(i);
			
			boolean ringIdea = isRingIdea(list, list, f1, f2);
			
			if (ringIdea) {
				listPID.add(zi);
			}
		}
		
		
		//理想已经找到了，接下来判断里面元素均为某个元的主理想
		
		//只能先计算list了
		ArrayList<ArrayList<T>> areadyPID = zijilist(list);
		for (int i = 0; i < list.size(); i++) {
			T x = list.get(i);
			
			ArrayList<T> asa = new ArrayList<>();
			
			
			for (int j = 0; j < list.size(); j++) {
				T t = list.get(j);
				
				T hanshu = f2.hanshu(x, t);
				asa.add(hanshu);
			}
			
			
			boolean ringIdea = isRingIdea(asa, list, f1, f2);
			
			if (ringIdea) {
				areadyPID.add(asa);
			}
			
		}
		
		//已经获得了生成的主理想
		
		a:for (int i = 0; i < listPID.size(); i++) {
			ArrayList<T> PID = listPID.get(i);
			
			
			for (int j = 0; j < areadyPID.size(); j++) {
				ArrayList<T> PID2 = areadyPID.get(j);
				
				boolean equel = Group.isEquel(PID, PID2);
				
				if (equel) {
					continue a;//只要有一个匹配上了，就进入下个循环即可
				}
			}
			
			return false;//当前PID如果匹配不上
			
		}
		
		
		
		
		
		
		
		return true;
	}


	
	
	/**
	 * 找出集合的所有子集
	 * @param <T>
	 * @param list
	 * @return
	 */
	private static <T> ArrayList<ArrayList<T>> zijilist(ArrayList<T> list) {
		List<int[]> indexall = new ArrayList<int[]>();
		for (int i = 1; i <= list.size(); i++) {
			List<int[]> combination = Shuffle.Combination(list.size(), i);
			indexall.addAll(combination);
		}
		
		ArrayList<ArrayList<T>> ziji = new ArrayList<ArrayList<T>>();//子集
		
		for (int i = 0; i < indexall.size(); i++) {
			int[] js = indexall.get(i);
			
			ArrayList<T> zi = new ArrayList<T>();
			for (int j = 0; j < js.length; j++) {
				zi.add(list.get(js[j]));
			}
			ziji.add(zi);
		}
		return ziji;
	}
	
	
	/**
	 * 
	 * (UFD): 整环 R 称作 唯一分解整环(UFD), 如果任何非单位都分解为素元的乘积.
	 * 
	 * 答案是找不到，因为有限群必然是循环群
	 * 
	 * 看上去很难想象
	 * 整数环就是，不可约的是素数，而非素数可以由素数的乘积唯一表达
	 * 
	 *  为 UFD 当且仅当 R 满足 ACCP(整环) 且 R 中任何不可约元均为素元.
	 * 
	 * (素元): 整环中元素 x属于 R\(R* 和上 {0}) 称为 素元, 如果 0!=(x)真包含于R 为素理想.		有点难
	 * 素元可以理解为不能再被其他元素计算表达
	 * 

	R 中任何不可约元均为素元，可理解为其中任何一个元素如果它不可约了，那么它就是素元，如果它可约，就可分解为
	素元的乘积，即可以由素元相乘来变成它

	 * 
	 * 任何一个PID都UFD
	 * 
	 * 
	 * 上面的定义是数学规范定义，其实白话说就是这个环中的任一对象可以由其他元素相乘唯一表示出来
	 * 就比如整数运算就是，非素数部分可以由素数相乘唯一表达
	 * 
	 * 要如何用代码判断呢？
	 * 不知道，有点无解，只有抽象表达
	 * 暴力点，先找出所有素元，然后判断非素元是否满足条件，分解为素元的乘积，这个有点难,任意一个元素分解为素元的组合
	 * 答案是找不到，因为有限群必然是循环群
	 * 
	 * 
	 * 
	 * @param <T>
	 * @param list
	 * @param f1
	 * @param f2
	 * @param e 乘的单位元
	 * @return 
	 */

	public static<T> boolean isUFD(ArrayList<T> list, ObjectFunction<T> f1, ObjectFunction<T> f2,T e) {
		
		
		if (1==1) {
			return false;
		}
		
		
		
		ArrayList<T> buffer = new ArrayList<T>();
		Collections.copy(buffer, list);
		buffer.remove(e);
		//素元找出来了
		ArrayList<T> findSUYUAN = findSUYUAN(list, f1, f2, e);
		
		buffer.removeAll(findSUYUAN);
		for (int i = 0; i < buffer.size(); i++) {
			
			//??
			
			
			
			
			
		}
		
		
		return true;
	}

	
	
	/**
	 * 找出集合中所有素元			有限环是没有素元的
	 * 
	 * (素元): 整环中元素 x属于 R\(R* 和上 {0}) 称为 素元, 如果 0!=(x)真包含于R 为素理想.		有点难
	 * 素元可以理解为不能再被其他元素计算表达,自己和自己的运算也算
	 * 
	 * @param <T>
	 * @param list
	 * @param f1
	 * @param f2
	 * @param e 乘的单位元
	 * @return
	 */
	public static<T> ArrayList<T> findSUYUAN(ArrayList<T> list, ObjectFunction<T> f1, ObjectFunction<T> f2,T e) {
		
		
		
		ArrayList<T> buffer = new ArrayList<T>();
		buffer.addAll(list);
		buffer.addAll(list);

		ArrayList<T> suyuan = new ArrayList<T>();
		suyuan.remove(e);
		
//		Collections.copy(buffer, list);
		Collections.copy(suyuan, list);

		for (int i = 0; i < buffer.size(); i++) {
			T t = buffer.get(i);
			if (t.equals(e)) {
				continue;
			}
			
			for (int j = 0; j < buffer.size(); j++) {
				T t2 = buffer.get(j);
				if (t2.equals(e)) {
					continue;
				}
				
				
				T hanshu = f2.hanshu(t, t2);
				if (suyuan.contains(hanshu)) {
					suyuan.remove(hanshu);
				}
				
				T hanshu2 = f2.hanshu(t2, t);
				
				if (suyuan.contains(hanshu2)) {
					suyuan.remove(hanshu2);
				}
				
				
				
			}
			
			
			
		}
		
		
		
		
		
		return suyuan;
	}
	
	
	
	
}
